package com.jzo2o.trade.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jzo2o.api.trade.dto.request.PayReqDTO;
import com.jzo2o.api.trade.dto.response.PayResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.common.constants.MqConstants;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.trade.enums.TradingStateEnum;
import com.jzo2o.trade.model.domain.Trading;
import com.jzo2o.trade.model.dto.TradeUpdateDTO;
import com.jzo2o.trade.service.IAliPayService;
import com.jzo2o.trade.service.IPayService;
import com.jzo2o.trade.service.ITradingService;
import com.jzo2o.trade.service.IWxPayService;
import com.jzo2o.trade.strategy.PayHandler;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class PayServiceImpl implements IPayService {

    private final ITradingService tradingService;
    private final IWxPayService wxPayService;
    private final RabbitTemplate rabbitTemplate;

    private final IAliPayService aliPayService;

    /**
     * 初始化支付渠道策略
     */
    private static final HashMap<Integer, PayHandler> payChannelMap = new HashMap<>();
    @PostConstruct
    public void initPayMap(){
        log.info("初始化支付类型和实现map");
        Map<String, PayHandler> beansOfType = SpringUtil.getBeansOfType(PayHandler.class);
        beansOfType.forEach((k, v) -> payChannelMap.put(v.getPayChannel(), v));
        log.info("初始化支付类型map成功{}", payChannelMap);
    }


    /**
     * 统一支付
     * 1. 创建交易订单
     * 2. 调用支付渠道
     *
     * @param reqDTO 请求参数
     * @return 统一支付结果
     */
    @Override
    public PayResDTO pay(PayReqDTO reqDTO) {
        PayResDTO payResDTO = new PayResDTO();
        //1.创建交易单
        Trading trading = tradingService.insertTrading(reqDTO);
        //2.调用支付渠道
        if (reqDTO.getTradingChannel()==null){
            throw new CommonException("请选择支付渠道");
        }

        try {
          /*  if (PayChannelEnum.WECHAT_PAY.equals(reqDTO.getTradingChannel())) {
                log.info("开始处理微信支付");
                payResDTO = wxPayService.pay(trading);
            }
            if (PayChannelEnum.ALI_PAY.equals(reqDTO.getTradingChannel())) {
                log.info("开始处理支付宝支付");
                payResDTO = aliPayService.pay(trading);
            }*/
            PayHandler payHandler = payChannelMap.get(reqDTO.getTradingChannel().getCode());
            payResDTO = payHandler.pay(trading);
        } catch (Exception e) {
            log.error("支付失败", e);
        }
        log.info("预交易单生成成功,等待用户付款");
        //3.更新交易单
        //3.1  更新状态
        trading.setTradingState(TradingStateEnum.FKZ.getCode());
        //3.2  更新第三方交易单号
        trading.setTransactionId(payResDTO.getTransactionId());
        tradingService.updateById(trading);
        return payResDTO;
    }

    @Override
    public void paySuccess(TradeUpdateDTO tradeUpdateDTO) {
        log.info("支付成功,回调内容是{}", tradeUpdateDTO);

        Trading trading = tradingService.getOne(Wrappers.<Trading>lambdaQuery().eq(Trading::getTradingOrderNo, tradeUpdateDTO.getTradingNo()));
        if (trading == null) {
            log.error("交易单不存在");
            throw new CommonException("交易单不存在");
        }
        //修改交易单
        trading.setTradingState(TradingStateEnum.YFK.getCode());
        trading.setTransactionId(tradeUpdateDTO.getTransactionId());
        tradingService.updateById(trading);
        //发送消息给订单服务
        log.info("发送消息给订单服务");
        HashMap<String, Object> transactionInfo = new HashMap<>();
        transactionInfo.put("orderNo", trading.getProductOrderNo());
        transactionInfo.put("tradingNo", tradeUpdateDTO.getTradingNo());
        transactionInfo.put("payTime", tradeUpdateDTO.getPayTime());
        transactionInfo.put("payChannel", tradeUpdateDTO.getPayChannel());
        rabbitTemplate.convertAndSend(MqConstants.Exchanges.TRADE, MqConstants.RoutingKeys.TRADE_UPDATE_STATUS, JSONUtil.toJsonStr(transactionInfo));
    }

    /**
     * 处理微信支付结果
     *
     * @param transaction 微信支付结果
     */
    @Override
    public void deal(Transaction transaction, Trading trading) {
        if (transaction == null) {
            log.info("微信支付结果为空");
            return;
        }
        //1 支付成功,封装调用支付成功的参数
        if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
            TradeUpdateDTO tradeUpdateDTO = new TradeUpdateDTO();
            tradeUpdateDTO.setTradingNo(transaction.getOutTradeNo());
            tradeUpdateDTO.setPayChannel(PayChannelEnum.WECHAT_PAY.getValue());
            tradeUpdateDTO.setPayTime(transaction.getSuccessTime());
            tradeUpdateDTO.setTransactionId(transaction.getTransactionId());
            this.paySuccess(tradeUpdateDTO);
        }
        //TODO 其他状态待处理
        //2 未支付,超过10分钟，关闭交易单
        if (transaction.getTradeState().equals(Transaction.TradeStateEnum.NOTPAY)) {
            LocalDateTime createTime = trading.getCreateTime();
            if (LocalDateTime.now().isAfter(createTime.plusMinutes(10))) {
                trading.setTradingState(TradingStateEnum.JYGB.getCode());
                trading.setTradingStateDesc("支付超时");
                tradingService.updateById(trading);
            }
        }
    }
}
